package com.mike.uaa.web;

import com.google.common.collect.Sets;
import com.mike.uaa.context.SecurityContext;
import com.mike.uaa.context.SecurityContextHolder;
import com.mike.uaa.context.SecurityContextImpl;
import com.mike.uaa.core.Authentication;
import com.mike.uaa.core.AuthenticationUtils;
import com.mike.uaa.web.redis.AuthenticationRepository;
import lombok.RequiredArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.NonNull;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.servlet.HandlerInterceptor;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author z
 */
@RequiredArgsConstructor
public class AuthenticationInterceptor implements HandlerInterceptor {

    private static final Logger log = LoggerFactory.getLogger(AuthenticationInterceptor.class);

    private static final Pattern pattern = Pattern.compile("^Bearer\\s+(?<token>[\\w-]+(?:\\.[\\w-]+)*)$");

    private final AuthenticationRepository authenticationRepository;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    private final Set<String> whitelist = Sets.newHashSet(
            "/actuator/**",
            "/error/**",
            "/login"
    );

    @Override
    public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull Object handler) throws Exception {

        String requestURI = request.getRequestURI();
        String tokenValue = extractBearerToken(request);
        if (tokenValue == null) {
            if (isWhitelistRequest(requestURI)) {
                return true;
            }
            // todo 跳转登录页
            response.sendRedirect("/login");
            return false;
        } else {
            // 获取登录信息并填充到当前线程中
            Authentication authentication = authenticationRepository.findById(tokenValue);
            if (AuthenticationUtils.unauthenticated(authentication)) {
                if (isWhitelistRequest(requestURI)) {
                    return true;
                }
                // TODO 跳转登录页
                response.sendRedirect("/login");
                log.debug("请求未认证，URL:{}", requestURI);
                return false;
            } else {
                SecurityContext context = new SecurityContextImpl(authentication);
                // 填充附加信息
                SecurityContextHolder.setContext(context);
                authenticationRepository.refresh(authentication);
                return true;
            }
        }
    }

    /**
     * 判断是否为白名单接口
     *
     * @param requestURI 从请求头中获取的请求接口地址
     * @return 返回该请求是否为白名单中的数据
     */
    private boolean isWhitelistRequest(String requestURI) {
        return this.whitelist.stream()
                .anyMatch(wl -> antPathMatcher.match(wl, requestURI));

    }

    /**
     * 使用正则表达式提取的增强版
     *
     * @param request HTTP请求对象
     * @return 提取到的Token（失败返回null）
     */
    private static String extractBearerToken(HttpServletRequest request) {

        String authorizationHeader = request.getHeader(RequestAttributes.AUTHORIZATION);
        if (authorizationHeader == null) return null;

        // 使用正则表达式匹配Bearer Token格式
        Matcher matcher = pattern.matcher(authorizationHeader);

        return matcher.find() ? matcher.group(RequestAttributes.TOKEN) : null;
    }

}
